<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 寄生组合式继承 ： 给每个子类都创建一个原型对象 让这个原型对象的隐式原型属性指向父类的原型对象。
    // js 继承
    function Person(name, age) {
        console.log(this);
        this.name = name;
        this.age = age;
    }
    console.log('父类原型对象：', Person.prototype);

    // 所有的Person的实例对象（孩子）都可以调用say方法
    Person.prototype.say = function () {
        console.log('hello');
    }



    function Student(name, age, grade) {
        Person.apply(this, [name, age])
        this.grade = grade;
    }


    // const childProperty = Object.create(Person.prototype)
    // // childProperty.constructor = Student
    // Object.defineProperty(childProperty, 'constructor', {
    //     enumerable: false,
    //     value: Student
    // })
    const childProperty = Object.create(Person.prototype, {
        constructor: {
            value: Student,
            enumerable: false,
        }
    })
    console.log('子类的原型对象：', childProperty)
    // 寄生组合式继承
    Student.prototype = childProperty

    Student.prototype.study = function () {
        console.log('study');
    }


    const zhangsan = new Student('张三', 18, 1)
    console.log(zhangsan);

    // console.log(zhangsan.name, zhangsan.age);
    zhangsan.say()



    // 对象属性描述符

    const obj = {
        name: '张三',
        age: 18,
        sex: '男'
    }
    // 获取对象属性的 属性描述
    console.log(Object.getOwnPropertyDescriptors(obj));

    console.log(Object.keys(obj))
    obj.name = '李四'
    obj.age = 19
    obj.sex = '女'
    console.log(obj);

    delete obj.name
    console.log(obj);


    // 更改对象属性描述符

    Object.defineProperty(obj, 'name', {
        value: '王五',
        writable: false, // 不可修改
        enumerable: false, // 不可枚举
        configurable: false // 不可删除
    })

    obj.name = '赵六'
    console.log(obj);
    console.log(Object.keys(obj))
    delete obj.name
    console.log(obj);


    // 总结：Object.defineProperty() 设置对象属性的描述符
    // 描述符：数据属性描述符 存取属性描述符

    console.log('==============存取属性描述符==============')
    const user = {
        name: '张三',
        age: 18,
        sex: '男',
        _sex: '男'
    }
    // user.sex = '不伦不类'

    Object.defineProperty(user, 'sex', {
        // 存取属性描述符 
        // 取值的方法
        get() {
            return user._sex
        },
        // 设置值的方法
        set(value) {
            console.log('设置属性值：', value);
            if (value === '男' || value === '女') {
                user._sex = value
            }
        }
    })

    user.sex = '不伦不类'
    console.log(user.sex);



    // 总结：
    // 设置属性的描述符：Object.defineProperty() 、 Object.defineProperties()
    // 数据属性描述符：
    // 1. value：属性值
    // 2. writable：属性值是否可修改
    // 3. enumerable：属性值是否可枚举
    // 4. configurable：属性值是否可删除
    // 存取属性描述符：
    // 1. get：取值方法
    // 2. set：设置值方法
    // 3. enumerable：属性值是否可枚举
    // 4. configurable：属性值是否可删除

    // Object.getOwnPropertyDescriptor()/ Object.getOwnPropertyDescriptors() 获取对象属性的描述符














</script>

</html>